#ifndef _PARETO_H_
#define _PARETO_H_

template
<
	typename Criterion
>
struct Maximize : public Criterion
{
    template
    <
        typename T
    >
    bool cmpr(const T& oldValue, const T& newValue)
    {
        return newValue >= oldValue;
    }
};

template
<
	typename Criterion
>
struct Minimize : public Criterion
{
    template
    <
       typename T
    >
    bool cmpr(const T& oldValue, const T& newValue)
    {
        return newValue <= oldValue;
    }
};

template
<
	typename Criterion,
	typename NumericType
>
struct Fixize : public Criterion
{
    template
    <
       typename T
    >
    bool cmpr(const T& oldValue, const T& newValue)
    {
        return abs(newValue - NumericType().value) <= abs(oldValue - NumericType().value);
    }
};

template
<
    typename ... Criteria
>
struct Pareto;

template
<
    typename Criterion,
    typename ... Criteria
>
struct Pareto<Criterion, Criteria ... >
{
    template
    <
        typename SignalSystem,
        typename Map
    >
	bool operator()(const SignalSystem& system, Map& oldResult, Map& newResult)
	{
	    newResult.template set<Criterion>( criterion(system) );
	    
	    if (!criterion.cmpr(
	            oldResult.template get<Criterion>(),
	            newResult.template get<Criterion>()))
	        return false;
	    
	    return pareto(system, oldResult, newResult);
	}
	
protected:
    Pareto<Criteria ...> pareto;
    Criterion criterion;
};
	
template
<
>
struct Pareto<>
{
    template
    <
        typename SignalSystem,
        typename Map
    >
    bool operator()(const SignalSystem& system, Map& oldResult, Map& newResult)
    {
        oldResult = newResult;
        return true;
    }
};

#endif // _PARETO_
